﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Labthink.PCSoft.UniversalHost4.DataAccess;
using Labthink.PCSoft.UniversalHost4.Model.Setting;
using Labthink.PCSoft.UniversalHost4.Utility;
using NLog;
using SystemSettings;
using Labthink.PCSoft.UniversalHost4.Model.User;

namespace Labthink.PCSoft.UniversalHost4.UserControls
{
    public partial class LoginControl
    {
        private readonly Logger _logger = LogManager.GetCurrentClassLogger();
        //public EventHandler<UserAndPermission> LoginSuccess;
        private readonly CustomInfo _info;
        public string Logo;
        private SafeInfo _safeInfo;
        private bool _isFirst = true;
        private readonly string _imgHome = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ImagesDiy");
        private NotifyManager _notify;

        private readonly System.Timers.Timer _capsLockCheckTimer;

        public LoginControl()
        {
            InitializeComponent();
            if (!Directory.Exists(_imgHome)) Directory.CreateDirectory(_imgHome);
            _capsLockCheckTimer = new System.Timers.Timer
            {
                Interval = 500
            };

            _capsLockCheckTimer.Elapsed += CapsLockCheckTimerTick;

            _info = Common.CustomInfo;
        }

        private void Login_OnLoaded(object sender, RoutedEventArgs e)
        {
            _capsLockCheckTimer.Start();
            var w = Window.GetWindow(this);
            _notify = NotifyManager.InstanceManager(w);
            Loading.Visibility = Visibility.Collapsed;
            TxtUserId.Focus();

            if (DebugHelper.IsInDebugMode() && !Common.IsFromLogout)
            {
                var up = DebugHelper.GetDebugUserPassword();
                if (up.Length > 1)
                {
                    TxtUserId.Text = up[0];
                    TxtPassword.Password = up[1];
                }
            }

            _safeInfo = Common.SafeInfo;

            if (_info != null)
            {
                TxtName.Text = _info.CustName;

                if (!string.IsNullOrEmpty(_info.CustLogo))
                {
                    string file = AppDomain.CurrentDomain.BaseDirectory + _info.CustLogo;
                    string dir = Path.GetDirectoryName(file);
                    if (!File.Exists(file))
                    {
                        if (Directory.Exists(dir))
                        {
                            Directory.Delete(dir, true);
                        }

                        Directory.CreateDirectory(dir);

                        //var sd =  await InstrumentManager.CurrentInstrument.Commands.GetCustomLogoAsync(Info.CustLogo);
                        string ff = "";
                        File.Move(ff, file);
                    }

                    var binReader = new BinaryReader(File.Open(file, FileMode.Open));
                    var fileInfo = new System.IO.FileInfo(file);
                    byte[] bytes = binReader.ReadBytes((int)fileInfo.Length);
                    binReader.Close();
                    var bmp = new BitmapImage();
                    bmp.BeginInit();
                    bmp.StreamSource = new MemoryStream(bytes);
                    bmp.EndInit();
                    Dispatcher.Invoke(() => { ImgLogo.Source = bmp; });
                }

                if (!string.IsNullOrEmpty(_info.CustThumb))
                {
                    string destFile = AppDomain.CurrentDomain.BaseDirectory + _info.CustThumb;
                    string dir = Path.GetDirectoryName(destFile);
                    if (!File.Exists(destFile))
                    {
                        if (Directory.Exists(dir))
                        {
                            Directory.Delete(dir, true);
                        }

                        Directory.CreateDirectory(dir);
                        //var sd = await InstrumentManager.CurrentInstrument.Commands.GetCustomLogoAsync(Info.CustThumb);
                        string ff = "";
                        File.Move(ff, destFile);
                    }

                    var binReader = new BinaryReader(File.Open(destFile, FileMode.Open));
                    var fileInfo = new System.IO.FileInfo(destFile);
                    byte[] bytes = binReader.ReadBytes((int)fileInfo.Length);
                    binReader.Close();
                    var bmp = new BitmapImage();
                    bmp.BeginInit();
                    bmp.StreamSource = new MemoryStream(bytes);
                    bmp.EndInit();
                    var ib = new ImageBrush
                    {
                        ImageSource = bmp
                    };

                    Dispatcher?.Invoke(() => { BorderBg.Background = ib; });
                }
            }

            Txt_PreviewMouseDown(null, null);

            if (DebugHelper.IsInDebugMode() && !Common.IsFromLogout)
            {
                btnLogin_Click(null, null);
            }
        }

        private void CapsLockCheckTimerTick(object sender, EventArgs e)
        {
            Dispatcher?.Invoke(() =>
            {
                try
                {
                    LblCapsLock.Visibility = Console.CapsLock ? Visibility.Visible : Visibility.Collapsed;
                }
                catch (TaskCanceledException exception)
                {
                }
            });
        }

        private void btnLogin_Click(object sender, RoutedEventArgs e)
        {
            _logger.Debug("login");
            Loading.Visibility = Visibility.Visible;

            if (string.IsNullOrEmpty(TxtUserId.Text))
            {
                TxtUserId.Focus();
                Loading.Visibility = Visibility.Collapsed;
                return;
            }

            if (string.IsNullOrEmpty(TxtPassword.Password))
            {
                TxtPassword.Focus();
                Loading.Visibility = Visibility.Collapsed;
                return;
            }

            var user = new User
            {
                LoginName = TxtUserId.Text,
                Password = TxtPassword.Password,
            };

            UserInfo u;

            u = UserRepository.GetUserByLoginName(user.LoginName);
            if (u == null)
            {
                _notify.ShowError(LanguageManager.GetLanguageValue("SD-UserNotExist"));
                Loading.Visibility = Visibility.Collapsed;
                return;
            }

            LogRepository.CurrentUser = u;
            if (u.IsLock.HasValue && u.IsLock.Value)
            {
                var baseInfo = ConfigAndSettings.GetBaseInfo();
                if (!baseInfo.Gmp && u.LockDate.HasValue &&
                    (DateTime.Now - u.LockDate.Value).TotalMinutes >= _safeInfo.LockTime)
                {
                    // 非GMP下，锁定时间超过设置的时间 自动解锁
                    u.IsLock = false;
                    u.LockDate = DateTime.Now;
                    UserRepository.LockUser(u.LoginName, false);
                    LogRepository.AddLog(LanguageManager.GetLanguageValue("OP-AutoUnlock", u.LoginName), "Manage", "SYSTEM", "SYSTEM");
                }

                if (u.IsLock.Value)
                {
                    _notify.ShowError(LanguageManager.GetLanguageValue("SD-UserLocked"));
                    _logger.Debug("用户被锁定");
                    Loading.Visibility = Visibility.Collapsed;
                    return;
                }
            }

            if (u.IsDelete.HasValue && u.IsDelete.Value)
            {
                _notify.ShowError(LanguageManager.GetLanguageValue("SD-UserDeleted"));
                _logger.Debug("用户被删除");
                Loading.Visibility = Visibility.Collapsed;
                return;
            }

            var hashedPassword = PasswordHash.HashPassword(user.Password, u.Salt);
            if (hashedPassword != u.Password)
            {
                if (_safeInfo.LockCount > 0)
                {
                    if (u.LastErrorDate.HasValue)
                        Common.LastErrorTime = u.LastErrorDate.Value;

                    Common.PasswordErrorCount++;
                    if ((DateTime.Now - Common.LastErrorTime).TotalMinutes >= _safeInfo.ResetTime)
                    {
                        Common.PasswordErrorCount = 0;
                    }

                    if (Common.PasswordErrorCount >= _safeInfo.LockCount && u.Role > 2)
                    {
                        //锁定
                        Common.LastErrorTime = DateTime.MinValue;
                        Common.PasswordErrorCount = 0;
                        UserRepository.LockUser(u.LoginName, true);
                        _notify.ShowError(string.Format(LanguageManager.GetLanguageValue("ErrorPwdLock"), _safeInfo.LockCount));
                        LogRepository.AddLog(LanguageManager.GetLanguageValue("OP-Locked"), "Manage");

                        Loading.Visibility = Visibility.Collapsed;
                        return;
                    }

                    _notify.ShowError(LanguageManager.GetLanguageValue("SD-PasswordError"));
                    _logger.Debug("密码输入错误");
                    if (u.LastErrorDate == null || u.LastErrorDate.Value == DateTime.MinValue)
                        u.LastErrorDate = DateTime.Now;

                    UserRepository.UpdateErrorTime(u.LoginName, DateTime.Now);
                    Loading.Visibility = Visibility.Collapsed;
                    return;
                }

                _notify.ShowError(LanguageManager.GetLanguageValue("SD-PasswordError"));
                _logger.Debug("密码输入错误");
                if (u.LastErrorDate == null || u.LastErrorDate.Value == DateTime.MinValue)
                    u.LastErrorDate = DateTime.Now;

                UserRepository.UpdateErrorTime(u.LoginName, DateTime.Now);
                Loading.Visibility = Visibility.Collapsed;
                return;
            }

            Common.CurrentUser = u;
            if (u.Role > 2 && DateTime.Now > u.ExpiresDate || u.IsFirst.HasValue && u.IsFirst.Value)
            {
                // 密码过期或者第一次登录，重新修改密码
                var frm = new ChangePassword { LoginName = TxtUserId.Text };
                bool? r = frm.ShowDialog(Application.Current.MainWindow);
                if (r.HasValue && r.Value)
                {
                    Loading.Visibility = Visibility.Collapsed;
                    TxtPassword.Password = frm.Tag + "";

                    // 重新获取
                    u = UserRepository.GetUserByLoginName(u.LoginName);
                    Common.CurrentUser = u;
                    btnLogin_Click(sender, e);
                    return;
                }
                else
                {
                    Loading.Visibility = Visibility.Collapsed;
                    return;
                }
            }

            UserAndPermission up = GetUserPermissions(u, true);
            Loading.Visibility = Visibility.Collapsed;
            LogRepository.AddLog(LanguageManager.GetLanguageValue("OP-UserLogin"), "Manage");
            _logger.Debug("login success");

            OnLoginSuccess(this, up);
            TxtUserId.Text = "";
            TxtPassword.Password = "";

            btnLogin.IsEnabled = true;
        }

        private UserAndPermission GetUserPermissions(UserInfo userInfo, bool isControl)
        {
            List<UserPermission> pers = RoleAndPerRepository.GetPermissionsByUid(userInfo.Id);
            Common.Permissions = pers;
            return new UserAndPermission
            {
                Info = userInfo,
                Permissions = pers,
                IsControl = isControl
            };
        }

        protected void OnLoginSuccess(object sender, UserAndPermission up)
        {
            Common.LoginSuccessEvent?.Invoke(this, up);
        }

        private void Txt_OnGotFocus(object sender, RoutedEventArgs e)
        {
            if (_isFirst)
            {
                _isFirst = false;
            }
        }

        private void Txt_PreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            pop1.IsOpen = false;
            pop1.IsOpen = true;
            pop1.StaysOpen = false;
            pop1.StaysOpen = true;
        }

        private void Txt_PreviewTouchDown(object sender, TouchEventArgs e)
        {
            pop1.IsOpen = false;
            pop1.IsOpen = true;
            pop1.StaysOpen = false;
            pop1.StaysOpen = true;
        }

        private void loginControl_Unloaded(object sender, RoutedEventArgs e)
        {
            _capsLockCheckTimer.Stop();
        }

        private void Txt_OnTextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
        {
            if (Txt1.Text != TxtUserId.Text) Txt1.Text = TxtUserId.Text;

        }
        private void Txt1_OnTextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
        {
            if (TxtUserId.Text != Txt1.Text) TxtUserId.Text = Txt1.Text;
        }

        private void Txt1_OnLostFocus(object sender, RoutedEventArgs e)
        {
            pop1.StaysOpen = false;
            pop1.IsOpen = false;
        }

        private void Txt_OnLostFocus(object sender, RoutedEventArgs e)
        {
            if (!Txt1.IsFocused) pop1.StaysOpen = false;
        }

        private void Pwd1_OnLostFocus(object sender, RoutedEventArgs e)
        {
            pop2.StaysOpen = false;
            pop2.IsOpen = false;
        }

        private void Pwd1_OnTextChanged(object sender, RoutedEventArgs e)
        {
            if (sender is System.Windows.Controls.PasswordBox txt)
            {
                if (txt.Password != TxtPassword.Password) TxtPassword.Password = txt.Password;
                if (txt.Password != Pwd1.Password) Pwd1.Password = txt.Password;
            }
        }

        private void Pwd_OnLostFocus(object sender, RoutedEventArgs e)
        {
            if (!Pwd1.IsFocused) pop2.StaysOpen = false;
        }

        private void Pwd_PreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            pop2.IsOpen = false;
            pop2.IsOpen = true;
            pop2.StaysOpen = false;
            pop2.StaysOpen = true;
        }

        private void Pwd_PreviewTouchDown(object sender, TouchEventArgs e)
        {
            pop2.IsOpen = false;
            pop2.IsOpen = true;
            pop2.StaysOpen = false;
            pop2.StaysOpen = true;
        }
    }
}
